/**
 * 事件驱动的任务队列
 * taskQueue ： 任务队列
 * maxTask ： 最大队列数
 * runningTask ： 当前运行任务数
 * total ： 总计执行成功的任务数
 *
 *
 */
const EventEmitter = require('events');
const util = require('./utils');

class MyEmitter extends EventEmitter {

    constructor(max, fn, finFn) {
        super();
        this.taskQueue = [];
        this.maxTask = max;
        this.runningTask = 0;
        this.name = '';
        this.total = 0;
        this.errSleep = 10000;

        //当单次任务结束后，触发该事件，
        this.on(MyEmitter.EVENT_TASK_FIN, (isInit) => {
            if(!isInit){
                // log.debug(`${this.name} 任务完成 queueLength = ${this.taskQueue.length}, running = ${this.runningTask}`);
                this.removeTask();
                this.total++;

                if(this.taskQueue.length === 0 && this.runningTask === 0){
                    this.emit(MyEmitter.EVENT_SYNC_FIN);
                    return;
                }
            }

            if(this.taskQueue.length > 0 && !this.isBusy()){
                this.runTask();
                let task = this.taskQueue.pop();
                fn(task)
                    .then(res => {
                    this.emit(MyEmitter.EVENT_TASK_FIN);
                })
                    .catch((err) => {
                    this.emit(MyEmitter.EVENT_TASK_ERR, err, task);
                });
                // log.debug(`${this.name} add task; queueLength = ${this.taskQueue.length}, running = ${this.runningTask}`);
            }
        });

        this.on(MyEmitter.EVENT_SYNC_FIN, () => {
            log.info(`${this.name} 同步完成 total task = ${this.total} queueLength = ${this.taskQueue.length}, running = ${this.runningTask}`);
            if(finFn){
                finFn(this.total);
            }
        });

        this.on(MyEmitter.EVENT_TASK_ERR, async (err, task) => {
            this.removeTask();
            log.error(`${this.name} 异常! 重试:${err.retry}, errMsg:${err.message}`);
            await util.sleep(this.errSleep);
            if(err.retry){
                this.addTask(task);
            }else{
                this.startup();
            }
        })
    }
}

MyEmitter.EVENT_TASK_FIN = 'TASK_FIN';
MyEmitter.EVENT_TASK_ERR = 'TASK_ERR';
MyEmitter.EVENT_SYNC_FIN = 'SYNC_FIN';

MyEmitter.prototype.addTask = function(tasks){
    if(!tasks && tasks !== 0){
        return;
    }
    if(!(tasks instanceof Array)){
        tasks = [tasks]
    }
    let length = Array.prototype.push.apply(this.taskQueue, tasks);

    if(length > 0){
        this.startup();
    }
    return length;
};

MyEmitter.prototype.startup = function(){
    this.emit(MyEmitter.EVENT_TASK_FIN, true);
};

MyEmitter.prototype.runTask = function(){
    return ++this.runningTask;
};
MyEmitter.prototype.removeTask = function(){
    return --this.runningTask;
};
MyEmitter.prototype.isBusy = function(){
    return this.runningTask >= this.maxTask;
};
MyEmitter.prototype.getQueueLength = function(){
    return this.taskQueue.length;
};

module.exports = MyEmitter;
